package com.qunar.train.mock.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by hongzhe.yao on 2018/8/28.
 *
 * dev测试代码增量覆盖情况工具
 */
public class DCC {

    //工程目录
    private String projectPath = "";
    private String branch = "origin/master";
    private String subProjectPath = "";

    public DCC() {
        getBasePath();
    }

    public DCC(String branch) {
        getBasePath();
        this.branch = branch;
    }

    private String getBasePath() {
        try {
            projectPath = Class.class.getClass().getResource("/").getPath().split("/target")[0];
        } catch (Exception e) {
            e.printStackTrace();
        }
        return projectPath;
    }

    /**
     * 获取覆盖率占比数据
     *
     * @param a     cov
     * @param b     add
     * @param scale 精度
     * @return dd.dd%
     */
    private String getPencent(int a, int b, int scale) {
        if (b == 0) {
            return "0.0% ";
        }
        BigDecimal b1 = new BigDecimal(Double.toString(a));
        BigDecimal b2 = new BigDecimal(Double.toString(b));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue() * 100 + "% ";
    }

    /**
     * 打印覆盖率统计数据
     *
     * @param className 类名
     * @param cov       覆盖行数
     * @param add       新增行数
     */
    private void myPrint(String className, int cov, int add) {
        String flag = "#########";
        String cont = " class: " + className + ", add: " + add + " 行, cov: " + cov + " 行, " + getPencent(cov, add, 4);
        System.err.println(flag + cont + flag);
    }

    /**
     * 解析codediff数据，dc数据的格式为k：类名，v：新增行数列表
     */
    public void parseDiff(JSONObject obj) {
        int covTotal = 0;
        int addTotal = 0;
        for (Map.Entry<String, Object> entry : obj.entrySet()) {
            String k = entry.getKey();
            JSONArray v = obj.getJSONArray(k);

            //过滤掉只有删除，没有新增的代码
            if (v.size() == 0) {
                continue;
            }

            //过滤掉非java文件、测试代码
            if ((!k.endsWith(".java")) || k.contains("src/test/java/")) {
                continue;
            }

            String fullPath = projectPath + "/" + k;
            String className = k.substring(k.indexOf("/java/") + 6, k.length() - 5).replace("/", ".");
            //暂时不过滤interface
//            if(new File(fullPath).exists()){
//                try {
//                    //过滤掉接口
//                    if(Class.forName(className).isInterface()) {
//                        continue;
//                    }
//                } catch (ClassNotFoundException e){
//                    e.printStackTrace();
//                }
//            } else {
//                continue;
//            }

            int res[] = parseReport(className, v);
            covTotal += res[0];
            //addTotal += v.size();
            addTotal += res[1];
        }
        myPrint("TOTAL", covTotal, addTotal);
    }

    /**
     * 解析覆盖报告，获取覆盖函数统计信息
     *
     * @param className 类名
     * @param arr       新增行数列表
     * @return 返回覆盖行数
     */
    public int[] parseReport(String className, JSONArray arr) {
        String htmlPath = projectPath + "/target/codecoverage-output/" + className.replace(".", "/") + ".html";
        if (!subProjectPath.equals("")) {
            htmlPath = subProjectPath + "/target/codecoverage-output/" + className.replace(".", "/") + ".html";
        }
        BufferedReader br = null;
        int covCount = 0;
        int addCount = 0;

        if (new File(htmlPath).exists()) {
            try {
                br = new BufferedReader(new FileReader(htmlPath));
                String line = br.readLine();
                String lastLine = "";
                int lineNum = 0;
                while (line != null) {
                    if (line.contains("<td class='line'>")) {
                        lastLine = line;
                        line = br.readLine();
                        if (!lastLine.contains("<td class='line'></td>")) {
                            lineNum = Integer.parseInt(lastLine.substring(lastLine.indexOf("class='line'>") + 13, lastLine.indexOf("</td>")));
                            if (lastLine.contains("<td class='count'>")) {
                                if (arr.contains(lineNum)) {
                                    addCount++;
                                    if (!lastLine.contains("<td class='count'>0<")) {
                                        covCount++;
                                    }
                                }
                            }
                        }
                        continue;
                    }

                    if (line.contains("<td class='count'>")) {
                        if (arr.contains(lineNum)) {
                            addCount++;
                            if (!line.contains("<td class='count'>0<")) {
                                covCount++;
                            }
                        }
                    }
                    line = br.readLine();
                }
                //myPrint(className, covCount, arr.size());
                myPrint(className, covCount, addCount);
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        int res[] = {covCount, addCount};
        return res;
    }

    @Deprecated
    public boolean fileterCode(String line) {
        if (line.contains("<pre class='comment'>")) { //注释
            return true;
        } else if (line.contains("<pre class='prettyprint'>    @")) { //注解
            return true;
        }
        return false;
    }

    @Deprecated
    public boolean isCovered(String line) {
        if (line.contains(" covered") || line.contains(" covered'") || line.contains("'covered ") || line.contains("'covered'")) {
            return true;
        }
        return false;
    }

    /**
     * 根据git diff 获取code diff信息，封装为json对象返回
     */
    public JSONObject getDiffCode() {
        JSONObject ret = new JSONObject();
        boolean isWindows = System.getProperty("os.name")
                .toLowerCase().startsWith("windows");
        String[] cmd = new String[200];
        if (isWindows) {
            //os:windows;
            String disk = this.projectPath.split("/")[1];
            String path = this.projectPath.split(":")[1];
            String cmd01 = disk + " & cd " + path + " & ";
            String cmd02 = "git diff " + this.branch;
            cmd = new String[]{"cmd.exe", "/c", cmd01 + cmd02};
        } else {
            //os:mac,ubantu;
            String cmd01 = "cd " + this.projectPath + ";";
            String cmd02 = "git diff " + this.branch;
            cmd = new String[]{"/bin/sh", "-c", cmd01 + cmd02};
        }

        BufferedReader br = null;
        try {
            Process p = Runtime.getRuntime().exec(cmd);
            br = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line = null;

            List<Integer> diff_lines = new ArrayList<>();
            String file_name = "";
            int current_line = 0;
            Pattern pattern = null;
            Matcher matcher = null;
            while ((line = br.readLine()) != null) {
                if (line.startsWith("diff --git")) {
                    if (!file_name.equals("")) {
                        ret.put(file_name, diff_lines);
                    }
                    pattern = Pattern.compile("b/(\\S+)$");
                    matcher = pattern.matcher(line);
                    while (matcher.find()) {
                        //System.err.println("group////" + matcher.group());
                        file_name = matcher.group(0).substring(2);
                    }
                    //diff_lines.clear();
                    diff_lines = new ArrayList<>();
                    current_line = 0;
                    continue;
                }

                pattern = Pattern.compile("@@ -\\d+,\\d+ \\+(\\d+),\\d+ @@");
                matcher = pattern.matcher(line);
                if (matcher.find()) {
                    current_line = Integer.parseInt(matcher.group(1)) - 1;
                } else if (line.startsWith("-")) {
                    continue;
                } else if (line.startsWith("+") && !line.startsWith("+++")) {
                    current_line += 1;
                    diff_lines.add(current_line);
                } else {
                    current_line += 1;
                }
            }
            ret.put(file_name, diff_lines);
            //System.err.println(ret.toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return ret;
    }

    /**
     * for 父子工程
     */
    public void setSubPro(String subProName) {
        subProjectPath = projectPath + "/" + subProName;
    }
}
